package com.cwx.mychat.config;

import com.cwx.mychat.filter.AuthenticationTokenFilter;
import com.cwx.mychat.login.LoginFailureHandler;
import com.cwx.mychat.login.LoginSuccessHandler;
import com.cwx.mychat.login.authentication.UsernameAuthenticationFilter;
import com.cwx.mychat.login.authentication.UsernameAuthenticationProvider;
import com.cwx.mychat.login.authentication.phone.PhoneAuthenticationFilter;
import com.cwx.mychat.login.authentication.phone.PhoneAuthenticationProvider;
import jodd.net.HttpMethod;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;


@Configuration
@EnableWebSecurity
@Slf4j
public class WebSecurityConfig {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private AuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 指定加密方式
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }


    @Bean
    protected SecurityFilterChain configure(HttpSecurity http) throws Exception {
        log.info("--------加载SpringSecurity配置--------");
        LoginSuccessHandler loginSuccessHandler = applicationContext.getBean(LoginSuccessHandler.class);
        LoginFailureHandler loginFailureHandler = applicationContext.getBean(LoginFailureHandler.class);
        //电脑端登录接口
        String usernameLoginPath = "/account/login";
        UsernameAuthenticationFilter usernameAuthenticationFilter = new UsernameAuthenticationFilter(new AntPathRequestMatcher(
                usernameLoginPath, HttpMethod.POST.name()),
                new ProviderManager(List.of(applicationContext.getBean(UsernameAuthenticationProvider.class))),
                loginSuccessHandler,
                loginFailureHandler);
        //手机端登录接口
        String phoneLoginPath = "/account/phoneLogin";
        PhoneAuthenticationFilter phoneAuthenticationFilter = new PhoneAuthenticationFilter(new AntPathRequestMatcher(
                phoneLoginPath, HttpMethod.POST.name()),
                new ProviderManager(List.of(applicationContext.getBean(PhoneAuthenticationProvider.class))),
                loginSuccessHandler,
                loginFailureHandler);

        http.authorizeHttpRequests((authorizeRequest) ->
                 authorizeRequest.requestMatchers("/account/login", "/account/checkCode",
                                 "/account/register", "/account/phoneLogin", "/account/getPhoneCode", "/ai/*")
                         .permitAll()
                         .anyRequest().authenticated()

                )
                //加入登录方式
                .addFilterBefore(usernameAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(phoneAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .logout(logout -> logout
                        .logoutUrl("/logout") //配置登出页面
                        .permitAll() //放行
                )
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class) //添加自定义过滤器在, 在UsernamePasswordAuthenticationFilter之前执行
                //支持跨域访问
                .cors(cors -> cors.configurationSource(configurationSource()))
                .csrf(AbstractHttpConfigurer::disable);
        return http.build();
    }


    /**
     * 跨域配置
     * @return
     */
    CorsConfigurationSource configurationSource(){
        log.info("--------开始进行跨域配置--------");
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOriginPattern("*");
        corsConfiguration.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return urlBasedCorsConfigurationSource;
    }

}
